#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <unistd.h>
#include <strings.h>
#include <memory>
#include <cstring>
#include "log.hpp"

class udpserver
{
public:
    udpserver(const uint16_t &port, const string &ip = "0.0.0.0")
        : _ip(ip), _port(port), _isrunning(false)
    {
        init();
    }
    ~udpserver()
    {
        close(_fd);
    }

    void init()
    {
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            log(ERROR, "open socket fail!");
            cout << "error: " << strerror(errno) << endl;
            exit(-1);
        }

        log(NOTICE, "socket create success!");

        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_port = htons(_port);

        int ret = bind(_fd, (const struct sockaddr *)&local, sizeof(local));
        if (ret == -1)
        {
            log(ERROR, "bind fail!");
            cout << "error: " << strerror(errno) << endl;
            exit(-1);
        }
        log(NOTICE, "bind success!");
    }

    void run()
    {
        _isrunning = true;
        char buffer[1024];
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        while (_isrunning)
        {
            // 获取数据(可以看作消费者消费数据)
            int n = recvfrom(_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (n == -1)
            {
                log(WARNING, "recvfrom fail!");
            }
            buffer[n] = '\0';

            // 下面对数据进行处理
            string info = "get message: ";
            info += buffer;
            cout << info << endl;

            // 下面将数据返回给客户端(看作生产者生产数据)
            n = sendto(_fd, info.c_str(), info.size(), 0, (const struct sockaddr *)&client, len);
            if (n == -1)
            {
                log(WARNING, "sendto fail!");
            }
        }
    }

private:
    int _fd;
    string _ip;
    uint16_t _port;
    bool _isrunning;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        log(ERROR,"argc should be 2");
        exit(-1);
    }
    uint16_t port=stoi(argv[1]);
    unique_ptr<udpserver> ptr(new udpserver(port));
    ptr->run();

    return 0;
}